package com.star.ms.admin.service.impl.user;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.star.ms.admin.service.user.RoleService;
import com.star.ms.common.dao.mapper.user.UrMapper;
import com.star.ms.common.dao.mapper.user.UserMapper;
import com.star.ms.common.vo.UserAddressCodeVo;
import com.star.ms.admin.dao.impl.user.AddressDAOImpl;
import com.star.ms.admin.dao.impl.user.UserDAOImpl;
import com.star.ms.admin.service.user.UrService;
import com.star.ms.common.api.EmailApi;
import com.star.ms.common.api.OssApi;
import com.star.ms.common.entity.address.Area;
import com.star.ms.common.entity.address.City;
import com.star.ms.common.entity.address.Province;
import com.star.ms.common.entity.api.Captcha;
import com.star.ms.common.entity.product.Product;
import com.star.ms.common.entity.user.Ur;
import com.star.ms.common.entity.user.User;
import com.star.ms.admin.service.user.UserService;
import com.star.ms.common.utils.CaptchaUtil;
import com.star.ms.common.vo.UserProvinceCountVo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
* @author uni10
* @description 针对表【ms_user】的数据库操作Service实现
* @createDate 2022-05-22 13:29:39
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService {

    @Autowired
    private UserDAOImpl userDAO;
    @Autowired
    private EmailApi api;
    @Autowired
    private OssApi api_oss;
    @Autowired
    private UrMapper userRoleMapper;
    @Autowired
    private UrService urService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private AddressDAOImpl addressDAO;

    @Override
    public boolean sendRegisterEmail(User user) {
        // 限制1: 用户的邮箱不能为空
        if("".equals(user.getEmail())) return false;
        // 1. 随机生成验证码
        Captcha captcha = CaptchaUtil.getRandomCaptcha(6);
        // 2. 插入到数据库
        boolean flag = userDAO.insertCaptcha(user, captcha);
        if(flag){
            return api.sendRegisterMail(user, captcha);
        }
        // 最终若未返回 true，就返回 false ，发送失败
        return false;
    }
    @Override
    public boolean sendRetrieveEmail(User user) {
        user.setUsercode(user.getEmail());
        // 限制1: 用户的邮箱不能为空
        if("".equals(user.getEmail())) return false;
        // 1. 随机生成验证码
        Captcha captcha = CaptchaUtil.getRandomCaptcha(6);
        // 2. 插入到数据库
        boolean flag = userDAO.insertCaptcha(user, captcha);
        if(flag){
            return api.sendRetrieveMail(user, captcha);
        }
        // 最终若未返回 true，就返回 false ，发送失败
        return false;
    }
    @Override
    public boolean verifyEmailCode(User user, String emailCode) {
        Captcha captcha = userDAO.selectCaptcha(user);
        return captcha.getInfo() != null &&
                captcha.getInfo().equals(emailCode) &&
                captcha.getLastTime() > 0;
    }


    @Override
    public User register(User user) {
        // 设置一些默认的信息
        user.setUsername(user.getUsercode());
        user.setAddress("北京市-北京市-海淀区-暂无");
        user.setBirthday(new Date(0));
        user.setGender(1);
        user.setImg("https://uni1024.oss-cn-hangzhou.aliyuncs.com/mall-system/public/%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F.png");
        // 设置随机盐
        String salt = UUID.randomUUID().toString().replace('-', 'A');
        // 将随机盐保存到用户中
        user.setSalt(salt);
        // 加密 密码
        Md5Hash md5Hash = new Md5Hash(user.getPassword(), salt, 1024);
        user.setPassword(md5Hash.toHex());
        // 保存用户到数据库
        return userDAO.insertUser(user);
    }

    @Override
    public User insertUser(User user, UserAddressCodeVo addressCodeVo) {
        // 首先查询省市区的信息
        Province province = addressDAO.selectProvinceByCode(addressCodeVo.getProvinceCode());
        City city = addressDAO.selectCityByCode(addressCodeVo.getCityCode());
        Area area = addressDAO.selectAreaByCode(addressCodeVo.getAreaCode());
        // 有的地区没有area，需要特殊处理
        if(area == null && city != null) area = new Area(1,"","",city.getCode());
        // 地址拼接
        String address = String.format("%s-%s-%s-%s", province.getName(), city.getName(), area.getName(), user.getAddress());
        // 设置默认头像
        user.setImg("https://uni1024.oss-cn-hangzhou.aliyuncs.com/mall-system/public/%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F.png");
        user.setAddress(address);
        user.setGender(1);
        // 密码特殊处理
        String salt = UUID.randomUUID().toString().replace('-', 'A');
        Md5Hash md5Hash = new Md5Hash(user.getPassword(), salt , 1024);
        user.setSalt(salt);
        user.setPassword(md5Hash.toHex());
        // 插入用户到数据库
        return userDAO.insertUser(user);
    }

    @Override
    public User login(User user) {
        User loginUser = null;
        if(user.getUsercode()!=null && user.getPassword()!=null) {
            loginUser = userDAO.selectByCode(user.getUsercode());
            // 封装一个 Token
            UsernamePasswordToken token = new UsernamePasswordToken(user.getUsercode(), user.getPassword(), false);
            // 获取主体
            Subject subject = SecurityUtils.getSubject();
            subject.login(token);
            // 验证成功后返回对象
            // 查询角色
            loginUser.setRole(roleService.getByUserCode(loginUser.getUsercode()));
        }
        return loginUser;
    }

    @Override
    public boolean verifyCodeExisted(User user) {
        return user != null && userDAO.selectByCodeAndPassword(user.getUsercode(), user.getPassword()) != null;
    }
    @Override
    public int saveImgByCode(String code, String imgUrl) {
        return userDAO.updateImgByCode(code, imgUrl);
    }

    @Override
    public boolean savePassword(User user, boolean needLogout) {
        // 如果需要注销的话先注销，然后在进行操作
        if(needLogout){
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
        }
        User user1 = userDAO.selectByCode(user.getUsercode());
        Md5Hash md5Hash = new Md5Hash(user.getPassword(), user1.getSalt() , 1024);
        user1.setPassword(md5Hash.toHex());
        return this.updateById(user1);
    }

    @Override
    public boolean saveEmail(User user) {
        return userDAO.updateSelective(user);
    }

    @Override
    public List<User> getListWithRole(Map<String, Object> condition) {
        return userDAO.selectWithRoleByMap(condition);
    }

    @Override
    public IPage<Product> getListWithRoleBySome(Map<String, Object> condition) {
        int pageNum = 1;
        int pageSize = 5;
        if(condition != null){
            pageNum = Integer.parseInt(condition.getOrDefault("pageNum", 1).toString());
            pageSize = Integer.parseInt(condition.getOrDefault("pageSize", 5).toString());
        }
        return userDAO.selectListWithRoleBySome(new Page<>(pageNum, pageSize), condition);
    }

    @Override
    public List<User> queryWithRoleByIds(List<Long> ids) {
        return userDAO.selectWithRoleByIds(ids);
    }

    @Override
    public boolean saveBaseById(User user, UserAddressCodeVo addressVo) {
        // 首先查询省市区的信息
        Province province = addressDAO.selectProvinceByCode(addressVo.getProvinceCode());
        City city = addressDAO.selectCityByCode(addressVo.getCityCode());
        Area area = addressDAO.selectAreaByCode(addressVo.getAreaCode());
        // 有的地区没有area，需要特殊处理
        if(area == null) area = new Area(1,"","",city.getCode());
        // 地址拼接
        String address = String.format("%s-%s-%s-%s", province.getName(), city.getName(), area.getName(), user.getAddress());
        user.setAddress(address);
        // 处理好用户的地址信息后，开始更新用户基本信息
        return userDAO.updateSelective(user);
    }

    @Override
    public int saveImgById(Long userId, String imgUrl) {
        return userDAO.updateImgById(userId, imgUrl);
    }

    @Override
    public boolean saveUsersWithRole(List<User> randomUser) {
        if(saveBatch(randomUser)){
            // 继续插入角色
            List<Ur> list = new LinkedList<>();
            for (User user : randomUser) {
                list.add(new Ur(user.getId(), 2));
            }
            return urService.saveBatch(list);
        }
        return false;
    }

    @Override
    public int getMaxId() {
        return userDAO.selectMaxUserId();
    }

    @Override
    public User getListById(Long userId) {
        return userDAO.selectById(userId);
    }

    @Override
    public List<UserProvinceCountVo> getListWithProvinceCount() {
        return userDAO.selectListWithProvinceCount();
    }

    @Override
    public User getByCode(String userCode) {
        return userDAO.selectByCode(userCode);
    }

    @Override
    public boolean retrieve(User user, String emailCode) {
        // 使用邮箱暂时代替用户账号进行验证
        user.setUsercode(user.getEmail());
        // 验证邮箱验证码
        if(verifyEmailCode(user, emailCode)){
            // 根据邮箱获取用户对象
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getEmail, user.getEmail());
            User newUser = this.getOne(wrapper);

            Md5Hash md5Hash = new Md5Hash(user.getPassword(), newUser.getSalt(), 1024);
            newUser.setPassword(md5Hash.toHex());

            return this.updateById(newUser);
        } else return false;
    }

    @Override
    public boolean hasExisted(String email) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail, email);
        return count(wrapper) > 0;
    }
}




